#include <Lucnx/global.h>
#include <Lucnx/printk.h>
#include <Lucnx/string.h>
#include <Lucnx/debug.h>
#include <Lucnx/task.h>

u64 gdt_ptr;
tss_t tss;

global_t gdt[128]; // 内核 gdt

u32 get_cr2()
{
    asm volatile("movl %cr2, %eax\n"); // eax 存储返回值
}

u32 get_cr0()
{
    asm volatile("movl %cr0, %eax\n");
}

static void global_init(global_t *desc, u32 base, u32 limit, u16 attr)
{
    desc->base1 = base & 0xFFFF;
    desc->base2 = (base & 0xFF0000) >> 16;
    desc->base3 = (base & 0xFF000000) >> 24;
    desc->limit1 = limit & 0xFFFF;
    desc->limit2_attr2 = ((limit >> 16) & 0xF) | ((attr >> 8) & 0xF) << 4;
    desc->attr1 = attr & 0xFF;
}

// 更新 TSS 中 esp0 的值为任务的内核栈
void update_tss_esp(task_t *task)
{
    tss.esp0 = (u32)task + PAGE_SIZE;
}

void gdt_init()
{
    memset(gdt, 0, sizeof(gdt));
    global_init(&gdt[0], 0, 0, 0);                 // NULL 描述符
    global_init(&gdt[1], 0, 0xFFFFF, K_CODE_ATTR); // 内核代码段
    global_init(&gdt[2], 0, 0xFFFFF, K_DATA_ATTR); // 内核数据段
    global_init(&gdt[4], 0, 0xFFFFF, U_CODE_ATTR); // 用户代码段
    global_init(&gdt[5], 0, 0xFFFFF, U_DATA_ATTR); // 用户数据段

    // 初始化 TSS
    memset(&tss, 0, sizeof(tss));
    tss.ss0 = SELECTOR_KERL_DATA;
    tss.iomap = sizeof(tss);
    global_init(&gdt[3], &tss, sizeof(tss) - 1, TSS_ATTR);

    gdt_ptr = (u64)(u32)gdt << 16 | sizeof(gdt) - 1;
    asm volatile("lgdt _gdt_ptr"); // 重新加载 gdt

    u16 tss_selector = SELECTOR_TSS;
    asm volatile("ltr %0\n" :: "g"(tss_selector)); // 加载 TSS

    INFOK("INFO", "Gdt init done");
}